package com.mcp.converter.domain.checker.impl;

import com.mcp.converter.shared.enums.CheckLevel;
import com.mcp.converter.domain.checker.*;
import com.mcp.converter.shared.response.sql.SQLElement;
import com.mcp.converter.shared.response.sql.SQLParseResult;
import com.mcp.converter.domain.rule.compatibility.CompatibilityRule;
import com.mcp.converter.domain.rule.manager.RuleManager;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 兼容性检测引擎实现类
 * 负责分析SQL语法树，检测不兼容点
 * @author zengxiong
 */
@Service
@Slf4j
public class CompatibilityCheckerImpl implements CompatibilityChecker {
    
    @Resource
    private RuleManager ruleManager;
    
    @Override
    public CompatibilityResult check(SQLParseResult parseResult) {
        return check(parseResult, CheckLevel.STANDARD);
    }
    
    @Override
    public CompatibilityResult check(SQLParseResult parseResult, CheckLevel checkLevel) {
        if (parseResult == null) {
            throw new IllegalArgumentException("SQL解析结果不能为空");
        }
        
        CompatibilityResult result = new CompatibilityResult(true);
        
        // 加载兼容性规则
        RuleManager.LoadResult loadResult = ruleManager.loadRules(RuleManager.RuleType.COMPATIBILITY);
        if (!loadResult.isSuccess()) {
            throw new RuntimeException("加载兼容性规则失败: " + loadResult.getMessage());
        }
        
        // 获取所有规则
        List<CompatibilityRule> rules = ruleManager.queryRules(
            RuleManager.RuleType.COMPATIBILITY, 
            new RuleManager.RuleQueryCondition()
        );
        
        // 遍历SQL元素树，检测不兼容点
        traverseAndCheck(parseResult.getElements(), rules, result, checkLevel);
        
        return result;
    }
    
    @Override
    public IncompatibilityDetail getDetail(IncompatiblePoint incompatiblePoint) {
        if (incompatiblePoint == null) {
            throw new IllegalArgumentException("不兼容点不能为空");
        }
        
        // 根据不兼容点查找对应的规则
        RuleManager.RuleQueryCondition condition = new RuleManager.RuleQueryCondition();
        condition.setType(incompatiblePoint.getType().name());
        condition.setName(incompatiblePoint.getName());
        
        List<CompatibilityRule> rules = ruleManager.queryRules(
            RuleManager.RuleType.COMPATIBILITY, 
            condition
        );

        if (rules.isEmpty()) {
            // 如果找不到对应的规则，返回一个默认的详情
            IncompatibilityDetail detail = new IncompatibilityDetail(incompatiblePoint);
            detail.setReason("未知的不兼容原因");
            detail.setSuggestion("请参考OceanBase官方文档");
            detail.setSeverity(IncompatibilityDetail.Severity.MEDIUM);
            return detail;
        } else {
            // 返回找到的第一个规则的详情
            IncompatibilityDetail detail = rules.get(0).getIncompatibilityDetail();
            detail.setIncompatiblePoint(incompatiblePoint);
            return detail;
        }
    }
    
    /**
     * 遍历SQL元素树，检测不兼容点
     * @param elements SQL元素列表
     * @param rules 兼容性规则列表
     * @param result 兼容性检测结果
     * @param checkLevel 检测级别
     */
    private void traverseAndCheck(List<SQLElement> elements, List<CompatibilityRule> rules, 
                                 CompatibilityResult result, CheckLevel checkLevel) {
        if (elements == null || elements.isEmpty()) {
            log.debug("[traverseAndCheck] 元素列表为空");
            return;
        }
        
        log.debug("[traverseAndCheck] 开始检查 {} 个元素", elements.size());
        
        for (SQLElement element : elements) {
            log.debug("[traverseAndCheck] 遍历元素: type={}, name={}, value={}", 
                     element.getType(), element.getName(), 
                     element.getValue() != null && element.getValue().length() > 50 
                         ? element.getValue().substring(0, 50) + "..." 
                         : element.getValue());
            
            // 特别关注函数元素
            if (element.getType() == com.mcp.converter.shared.enums.SQLElementType.FUNCTION) {
                log.debug("[traverseAndCheck] 发现函数元素: {}", element.getName());
            }
            
            // 检查当前元素是否匹配任何规则
            for (CompatibilityRule rule : rules) {
                if (shouldApplyRule(rule, checkLevel) && rule.matches(element)) {
                    log.info("[traverseAndCheck] 规则命中: rule={}, elementName={}, elementType={}", 
                            rule.getName(), element.getName(), element.getType());
                    // 创建不兼容点
                    IncompatiblePoint incompatiblePoint = createIncompatiblePoint(element, rule);
                    // 添加到结果中
                    result.addIncompatiblePoint(incompatiblePoint);
                } else if (element.getType() == com.mcp.converter.shared.enums.SQLElementType.FUNCTION) {
                    // 对于函数元素，记录未匹配的情况（调试用）
                    log.debug("[traverseAndCheck] 函数 {} 未匹配规则: {}", element.getName(), rule.getName());
                }
            }
            
            // 递归检查子元素
            if (element.hasChildren()) {
                log.debug("[traverseAndCheck] 递归检查子元素: {}", element.getChildren().size());
                traverseAndCheck(element.getChildren(), rules, result, checkLevel);
            }
        }
        
        log.debug("[traverseAndCheck] 检查完成");
    }
    
    /**
     * 根据检测级别判断是否应用规则
     * @param rule 兼容性规则
     * @param checkLevel 检测级别
     * @return 是否应用规则
     */
    public boolean shouldApplyRule(CompatibilityRule rule, CheckLevel checkLevel) {
        IncompatibilityDetail detail = rule.getIncompatibilityDetail();
        if (detail == null || detail.getSeverity() == null) {
            return true;
        }

        return switch (checkLevel) {
            case STRICT ->
                // 严格模式下检测所有规则
                    true;
            case STANDARD ->
                // 标准模式下不检测LOW级别的规则
                    detail.getSeverity() != IncompatibilityDetail.Severity.LOW;
            case LOOSE ->
                // 宽松模式下只检测CRITICAL和HIGH级别的规则
                    detail.getSeverity() == IncompatibilityDetail.Severity.CRITICAL || detail.getSeverity() == IncompatibilityDetail.Severity.HIGH;
        };
    }
    
    /**
     * 创建不兼容点
     * @param element SQL元素
     * @param rule 兼容性规则
     * @return 不兼容点
     */
    private IncompatiblePoint createIncompatiblePoint(SQLElement element, CompatibilityRule rule) {
        IncompatiblePoint incompatiblePoint = new IncompatiblePoint(
            rule.getIncompatibilityType(),
            element.getName(),
            element.getValue()
        );
        
        // 设置位置信息
        if (element.getPosition() != null) {
            IncompatiblePoint.Position position = new IncompatiblePoint.Position(
                element.getPosition().getLine(),
                element.getPosition().getColumn(),
                element.getPosition().getStartIndex(),
                element.getPosition().getEndIndex()
            );
            incompatiblePoint.setPosition(position);
        }
        
        // 设置元素引用
        incompatiblePoint.setElement(element);
        
        return incompatiblePoint;
    }
}
